iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0
Modern Web

JS 忍者訓練計畫系列 第 11

閉包封鎖之術(下) Day10

  • 分享至 

  • xImage
  •  

有好多好多的函式跟閉包在這裡!進階用法要注意上下文綁定的內容,還可以使用 prototype 功能,去增加函式的使用行為。但進階用法需要更小心使用。

每個透過閉包存取資訊的函式,都有條「鎖腳鏈」,拖著資訊、附加在函式上,所以閉包極為有用,但並非不會造成負擔與花費,上述那些資訊都會佔用記憶體,直到 JavaScript 執行引擎確定不再需要(也就是能夠被當成垃圾、被系統回收),或是直到頁面消失。

這章想學到什麼?

  • getter 與 setter 控制閉包私有變數
  • fetch 使用 callback 函式
  • Bind 從沒有到原生提供如何形成
  • split 與正規表達式(與閉包無關)
  • parital apply 預先定義好新函式,在某時間點呼叫 (類似中介函式)
  • memoized 改寫函式行為(此為隱性觸發功能,小心服用) 與 function wrapping 技巧
  • 複習立即函式

程式碼閱讀練習與撰寫

getter 與 setter 控制閉包私有變數

function Account() {
    var deposit = 0;
    this.save = function () {
        deposit++;
    }
    this.take = function () {
        deposit > 0 ? deposit-- : 0
    }
    this.getTotal = function () {
        return deposit;
    }
}

var myAccount = new  Account()
myAccount.save()
myAccount.getTotal() //1
myAccount.take()
myAccount.getTotal() //0

fetch 使用 callback 函式

fetch('https://jsonplaceholder.typicode.com/todos/10')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson);
  });

Bind 從沒有到原生提供如何形成

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  
  return function(){
      return fn.apply(object, args.concat(Array.prototype.slice.call(arguments)))
  }
}

var myObject = {};
function myFunction(){
    return this == myObject;
}
aFunction = myFunction.bind(myObject)

split 與正規表達式(與閉包無關)

var elements1 = "val1,val2,val3".split(/,\s*/);
var elements2 = "val1,val2,val3".split(/,\s*/);
var elements3 = "val1,  val2, val3".split(/,\s*/);

//\s為空白 * 為0~多個,意思指逗點加空白為切割字串方式,所以 1 ,2 ,3 會得到相同結果,擷取出的字串不包含空白字元

parital apply 預先定義好新函式,在某時間點呼叫 (類似中介函式)

Function.prototype.partial = function() {
    var fn = this, args = Array.prototype.slice.call(arguments);
    return function(){
        var arg = 0;
        for (var i = 0; i < args.length && arg < arguments.length; i++) {
        if(args[i] === undefined) {
            args[i] = arguments[arg++]
        }
        }
        return fn.apply(this, args);
    }
}

var delay = setTimeout.partial(undefined, 3000);
delay(function(){
    console.log("3 sec later")
})

memoized 改寫函式行為(此為隱性觸發功能,小心服用) 與 function wrapping 技巧

memoized 改寫函式行為(此為隱性觸發功能,小心服用)

Function.prototype.memoized = function(key){
    this._values = this._values || {};
    return this._values[key] !== undefined ? this._values[key] : this._values[key] = this.apply(this, arguments);
}

Function.prototype.memoize = function(){
    var fn = this;
    return function(){
        return fn.memoized.apply(fn, arguments);
    }
}

var isPrime = (function(num) {
    var prime = num != 1;
    for (var i = 2; i < num; i++) {
        if(num % i == 0) {
            prime = false;
            break;
        }
    }
    return prime;
}).memoize();

console.log(isPrime(12)) //false
console.log(isPrime(2147483647)) //true,會跑超久
console.log(isPrime(2147483647)) //true,不用等

function wrapping 技巧

function wrap(object, method, wrapper) {
    var fn = object[method];
    
    return object[method] = function() {
        return wrapper.apply(this, [fn.bind(this)].concat(Array.prototype.slice.call(arguments)))
    }
}

if(Prototype.Browser.Opera) {
    wrap(Element.Methods, "readAttribute", function(original, elem, attr) {
    return attr == "title" ? elem.title : original(elem, attr)
    })
}

//有點像 polyfill,例如想修改 forEach 為倒序
let fruits = ['apple', 'banana', 'peach']

Array.prototype.forEach = function(callback){
      for(i=this.length; i > -1; i--){
          callback(this[i])
      }
  }
fruits.forEach(function(element){
    console.log(element)
  })

複習立即函式

  • 建立函式實體
  • 執行函式
  • 丟棄函式(在敘述之後,就沒有人指向該函式)
//忍者裡的奇怪例子
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++) (function(n){
    divs[n].addEventListener("click", function(){
        console.log("I am here!")
    }, false)
})(i);

參考資料

https://developer.mozilla.org/zh-TW/docs/Web/API/Fetch_API/Using_Fetch
https://jsonplaceholder.typicode.com/
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/split


上一篇
閉包封鎖之術(上) Day9
下一篇
原型之物件導向(上) Day11
系列文
JS 忍者訓練計畫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言